<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
  // 定义一个LinkedList类! 首先明白链表的特点是什么? 链表里面保存着Node节点,每一个Node节点都有自己的元素,并且LinkedList的next都会指向下一个节点
  // 链表类呢都有个head指向第一个节点和一个length计算链表的长度!
  // 链表是在最后面添加一个元素的

   function LinkedList(){

   function Node(value){
    // 可以根据传入的参数,创建内部节点的实例
     this.value = value
    //  里面包含了节点下一个的指向!
     this.next = null
   }
    //  链表头
     this.head = null
    //  链表长度为0
     this.length = 0
   
    // 给实例添加一个append方法(实例上面的方法都定义在原型上)
   LinkedList.prototype.append = function(value){
    // 根据传入的元素,创建一个实例对象
    const newNode = new Node(value)
    //如果this.head=null即链表中一个元素都无
    if(this.head ===null){
       this.head = newNode
    }else{
         let current = this.head
    //  这样就可以遍历到链表的尾部!并在其最后添加一个元素!
        while(current.next){
          current = current.next
        }
      //现在current就是最后一个元素,使其指向新创建的新节点
       current.next = newNode

      // 最后别忘记了,增加一个元素,链表的总长度要求+1
       this.length++
    }
    }

      // toString方法
    LinkedList.prototype.toString = function(){
        var listString = ''   //给每一个链表的元素都添加字符穿的方式即可
        let current = this.head
        // 很简单那,遍历每一个链表,给每一个元素加上字符串,然后返回即可
        while(current){
          listString += ','+ current.value
          current = current.next
        }
        // 截取每一个并返回
        return listString.slice(1)
    }
   
    
      // 自己封装,通过索引获取当前元素
   LinkedList.prototype.getvalueByIndex = function (position){
          let current = this.head
          for(var i = 0;i < position;i++){
            current = current.next
          }
          return current.value
   }


    //  insert方法,根据下标来添加一个元素
    LinkedList.prototype.insert = function(position,value){
          //判断角标有没有越界
      if(position < 0|| position >=this.length)  return false
          const newNode = new Node(value)
          let  current = this.head
          let  previous = null
          // 如果插入的元素就是第一个则让新节点指向第一个节点,head指向新节点即可!
       if( position === 0 ){
          newNode.next = current
          this.head = newNode
      }else{
        // 这样可以让前一个previos指向下一个节点,直接获取
          for( var i = 0;i < position; i++ ){
             previous = current
             current = current.next
          }
           previous.next = newNode
           newNode.next = current
      }
            this.length++
            return true
    }
      
    //  根据索引来删除一个元素,和上面的方法如出一辙
    LinkedList.prototype.removeAt = function (position){
      if(position < 0 ||position >= this.length)  return null
      let current = this.head
      let previous = null
      for(var i = 0; i < position; i++){
        previous = current
        current = current.next
      }
      // 只需要让之前的元素指向下下个元素即可删除下一个节点!
      previous.next = current.next

      this.length--
      return current.value  //返回被移除的元素
    }

    //通过元素来获取当前的索引值!
    LinkedList.prototype.indexOf = function(value){
        let current = this.head
         index = 0
        while(current){
        if(value = this.value){
          return index
        }
        index++
        current = current.next
      }
        return -1
      }


    // 删除一个元素,方法
    LinkedList.prototype.remove = function(value){
        const index =this.indexOf(value)
        this.removeAt(index)
    }

  // 判断链表是否为空
  LinkedList.prototype.isEmpty = function(){
    return this.length === 0?true:false
  }
  
  // 获取链表的长度
   LinkedList.prototype.size = function (){
     return this.length
   }

  // 获取链表的第一个节点!
  LinkedList.prototype.Firstvalue = function (){
    return this.head.value
  }

     }
 
  //  总结:只要把握insert方法和removeAt方法其他方法都是简单的.这两个方法如出一辙,都是先判断好角标有没有越界,然后根据previos和current两个不断的遍历来达到目的
  // 总的来说就是把握好removeAt和insert方法即可!不要忘记this.length要发生变化哦!


  </script>
</body>
</html>